home *** CD-ROM | disk | FTP | other *** search
/ Linux Cubed Series 7: Sunsite / Linux Cubed Series 7 - Sunsite Vol 1.iso / system / admin / linuxcon.000 / linuxcon / linuxconf-1.6 / dialog / multi.c < prev    next >
C/C++ Source or Header  |  1996-08-01  |  10KB  |  452 lines

  1. #include <stdio.h>
  2. #include <string.h>
  3. #include "diadef.h"
  4. #include "dialog.h"
  5. #include "internal.h"
  6.  
  7. /*
  8.     Evaluate the size of a text in a string.
  9.     (number of line, maximum width)
  10.  
  11.     The string may contain tabs.
  12.     Return the number of line
  13. */
  14. int dialog_textsize (const char *txt, int *width)
  15. {
  16.     int nbline=1;
  17.     int maxlen = 0;
  18.     if (txt != NULL){
  19.         const char *lastpt = txt;
  20.         char *pt = strchr (txt,'\n');
  21.         while (pt != NULL){
  22.             int len = 0;
  23.             while (lastpt < pt){
  24.                 if (*lastpt == '\t'){
  25.                     if (len % 8 == 0) len++;
  26.                     while (len % 8 != 0) len++;
  27.                 }else{
  28.                     len++;
  29.                 }
  30.                 lastpt++;
  31.             }
  32.             len += 2;
  33.             nbline++;
  34.             if (len > maxlen) maxlen = len;
  35.             lastpt = pt+1;
  36.             pt = strchr (lastpt,'\n');
  37.         }
  38.         {
  39.             int lastlen = strlen (lastpt);
  40.             if (lastlen > maxlen) maxlen = lastlen;
  41.         }
  42.     }
  43.     *width = maxlen;
  44.     return nbline;
  45. }
  46.  
  47. /*
  48.     Open a centered window
  49. */
  50. WINDOW *dialog_openwin(
  51.     int height,
  52.     int width)
  53. {
  54.     WINDOW *dialog;
  55.     if (COLS == 0){
  56.         fprintf (stderr,"You forget init_dialog\n");
  57.         exit (-1);
  58.     }else{
  59.         /* center dialog box on screen */
  60.         int x = (COLS - width)/2;
  61.         int y = (LINES - height)/2;
  62.         // Open larger to draw the shadow
  63.         int height_1 = height+1;
  64.         if (height_1 > LINES) height_1 = LINES;
  65.         int width_2 = width+2;
  66.         if (width_2 > COLS) width_2 = COLS;
  67.         dialog = newwin(height_1, width_2, y, x);
  68.         keypad(dialog, TRUE);
  69.     }
  70.     return dialog;
  71. }
  72.  
  73. void dialog_draw (
  74.     WINDOW *dialog,
  75.     const char *title,
  76.     const char *intro,
  77.     int height,
  78.     int width)
  79. {
  80.     draw_box(dialog, 0, 0, height, width, dialog_attr
  81.         , border_attr, border_attr_shadow);
  82.     draw_shadow(dialog, 0, 0, height, width);
  83.  
  84.     if (title != NULL) {
  85.         wattrset(dialog, title_attr);
  86.         wmove(dialog, 0, (width - strlen(title))/2 - 1);
  87.         waddch(dialog, ' ');
  88.         waddstr(dialog, (char*)title);
  89.         waddch(dialog, ' ');
  90.     }
  91.     if (intro != NULL){
  92.         int posy = 1;
  93.         while (*intro != '\0'){
  94.             char tmp[100];
  95.             char *pt = tmp;
  96.             while (*intro != '\0' && *intro != '\n'){
  97.                 *pt++ = *intro++;
  98.             }
  99.             *pt = '\0';
  100.             if (*intro == '\n') intro++;
  101.             wmove (dialog,posy++,2);
  102.             waddstr (dialog,tmp);
  103.         }
  104.     }
  105. }
  106.  
  107. /*
  108.     Compute the layout of the dialog based on its content.
  109. */
  110. PRIVATE void DIALOG::setup ()
  111. {
  112.     int fields_height = getnb()==0 ? 0 : getnb()+2;
  113.     int button_height = 3;
  114.     int frame_space = 3;
  115.     int max_prompt = 0;
  116.     int intro_height= 0;
  117.     int intro_width = 0;
  118.     if (!intro.is_empty()){
  119.         intro_height = dialog_textsize(intro.get(),&intro_width);
  120.         intro_width += 4;
  121.     }
  122.     nbvisible = getnb();
  123.     height = intro_height + frame_space + button_height + fields_height;
  124.     if (height > 24){
  125.         nbvisible -= height - 24;
  126.         height = 24;
  127.     }
  128.     int max_field = 0;
  129.     for (int i=0; i<getnb(); i++){
  130.         FIELD *f = getitem(i);
  131.         char *prompt = f->prompt;
  132.         int len = strlen(prompt);
  133.         if (len > max_prompt) max_prompt = len;
  134.         f->box.y  = 3 + intro_height + i - offset;
  135.         if (max_field < f->box.width) max_field = f->box.width;
  136.     }
  137.     int data_width = max_field + 5 + max_prompt;
  138.     width = data_width;
  139.     if (width < intro_width) width = intro_width;
  140.     int title_len = title.getlen();
  141.     int button_len = buttons->evalwidth();
  142.     if (title_len > width) width = title_len;
  143.     if (button_len > width) width = button_len;
  144.     buttons->setup (height-3,width);
  145.     // Try to center the data box if there is no prompt
  146.     if (data_width < width && max_prompt < 2){
  147.         max_prompt += (width - data_width)/2;
  148.     }
  149.     for (i=0; i<getnb(); i++){
  150.         FIELD *f = getitem(i);
  151.         f->box.x = max_prompt + 3;
  152.         f->box.width = max_field;
  153.     }
  154. }
  155.  
  156. /*
  157.     Set the offset of the first visible field and ajust
  158.     the coordinate of all field so they will know where to draw
  159.     themselve.
  160. */
  161. PRIVATE void DIALOG::setoffset (int newoff)
  162. {
  163.     int diff = newoff - offset;
  164.     offset = newoff;
  165.     for (int i=0; i<getnb(); i++){
  166.         getitem(i)->box.y -= diff;
  167.     }
  168. }
  169.  
  170. /*
  171.     Draw all visible field
  172. */
  173. PROTECTED void DIALOG::drawf(WINDOW *dialog)
  174. {
  175.     int lastf = getnb();
  176.     if (lastf - offset > nbvisible) lastf = offset + nbvisible;
  177.     for (int i=offset; i<lastf; i++){
  178.         getitem(i)->draw (dialog);
  179.     }
  180. }
  181. /*
  182.     Send a message to all fields of a dialog
  183. */
  184. PRIVATE void DIALOG::processmsg(WINDOW *dialog, FIELD_MSG &msg)
  185. {
  186.     int lastf = getnb();
  187.     int last_visible = offset + nbvisible;
  188.     for (int i=0; i<lastf; i++){
  189.         getitem(i)->processmsg (dialog,msg
  190.             ,i >= offset && i < last_visible);
  191.     }
  192. }
  193. /*
  194.     Draw the complete dialog
  195. */
  196.  
  197. PRIVATE void DIALOG::draw (WINDOW *dialog)
  198. {
  199.     dialog_draw (dialog,title.get(),intro.get(),height,width);
  200.     wattrset(dialog, dialog_attr);
  201.     if (getnb()>0){
  202.         /* Draw the input field box */
  203.         FIELD *finfo = getitem(offset);
  204.         draw_box(dialog, finfo->box.y-1, finfo->box.x-1, nbvisible+2
  205.             , finfo->box.width+2
  206.             , inputbox_attr, border_attr_shadow,border_attr);
  207.         drawf(dialog);
  208.     }
  209.     buttons->draw (dialog,button);
  210. }
  211. PRIVATE void DIALOG::drawarrow_if(
  212.     WINDOW *win,
  213.     bool condition,    // Should it be drawn
  214.     bool & flag,    // Does the carac is already drawn
  215.     bool top,    // Top or bottom arrow
  216.     chtype carac)    // Char to print
  217. {
  218.     if (getnb() > 0){
  219.         FIELD *f = getitem(offset);
  220.         int posx = f->box.x + f->box.width/2;
  221.         int posy = top ? f->box.y - 1 : f->box.y + nbvisible;
  222.         if (condition){
  223.             if (!flag){
  224.                 flag = true;
  225.                 wmove (win,posy,posx);
  226.                 wattrset(win,inputbox_border_attr);
  227.                 waddch (win,carac);
  228.             }
  229.         }else if (flag){
  230.             flag = false;
  231.             wmove (win,posy,posx);
  232.             wattrset(win,inputbox_border_attr);
  233.             waddch (win,ACS_HLINE);
  234.         }
  235.     }
  236. }
  237.  
  238. /*
  239.     Interpret a cursor key.
  240.     Return -1 if it not a cursor key
  241. */
  242. PROTECTED VIRTUAL int DIALOG::keymove (WINDOW *dialog, int key, int &nof)
  243. {
  244.     int ret = 0;
  245.     switch (key){
  246.     case KEY_PPAGE:
  247.         if (offset == 0){
  248.             nof = 0;
  249.         }else{
  250.             int newoff = offset - nbvisible;
  251.             if (newoff < 0) newoff = 0;
  252.             nof -= (offset - newoff);
  253.             setoffset(newoff);
  254.             drawf(dialog);
  255.         }
  256.         break;
  257.     case KEY_UP:
  258.         nof--;
  259.         if (nof < offset){
  260.             if (offset > 0){
  261.                 setoffset(offset -1);
  262.                 drawf(dialog);
  263.             }else{
  264.                 nof = 0;
  265.             }
  266.         }
  267.         break;
  268.     case KEY_NPAGE:
  269.         {
  270.             int maxoffset = getnb() - nbvisible;
  271.             if (maxoffset < 0) maxoffset = 0;
  272.             if (offset >= maxoffset){
  273.                 nof = getnb()-1;
  274.             }else{
  275.                 int newoff = offset + nbvisible;
  276.                 if (newoff > maxoffset) newoff = maxoffset;
  277.                 nof += (newoff - offset);
  278.                 setoffset(newoff);
  279.                 drawf(dialog);
  280.             }
  281.         }
  282.         break;
  283.     case KEY_DOWN:
  284.         nof++;
  285.         if (nof < getnb()){
  286.             if (nof == offset + nbvisible){
  287.                 setoffset (offset+1);
  288.                 drawf(dialog);
  289.             }
  290.         }else{
  291.             nof--;
  292.         }
  293.         break;
  294.     default:
  295.         ret = -1;
  296.     }
  297.     return ret;
  298. }
  299. DIALOG_MODE dialog_mode = DIALOG_CURSES;
  300. /*
  301.     Set the basic user interface mode.
  302.     This function is generally called at startup time
  303. */
  304. void dialog_setmode (DIALOG_MODE mode)
  305. {
  306.     dialog_mode = mode;
  307. }
  308.  
  309. PUBLIC DIALOG::DIALOG()
  310. {
  311.     buttons = new BUTTONS_INFO;
  312.     offset = 0;
  313. }
  314. PUBLIC DIALOG::~DIALOG()
  315. {
  316.     html_forgetdialog (this);
  317.     delete buttons;
  318. }
  319. /*
  320.     Multiple field dialog.
  321.     All field are shown one under each others
  322.  */
  323. PUBLIC MENU_STATUS DIALOG::edit(
  324.     const char *_title,        // Main title
  325.     const char *_intro,        // Mini help describing the purpose
  326.                     // of the dialog
  327.     const char *helpfile,        // Help text in a file or NULL
  328.     int &nof,            // Start editing on which field
  329.                     // Will contain the current field.
  330.     int but_options)        // MENUBUT_xxxxx
  331. {
  332.     MENU_STATUS ret = MENU_NULL;
  333.     button = getnb()==0 ? 0 : -1;    // Button currently selected
  334.     title.setfrom (_title);
  335.     intro.setfrom (_intro);
  336.     buttons->set (but_options,helpfile);
  337.     setup ();
  338.  
  339.     if (dialog_mode == DIALOG_HTML){
  340.         ret = edithtml (nof);
  341.     }else{
  342.         ret = editterm (nof,but_options);
  343.     }
  344.     if (ret == MENU_ACCEPT){
  345.         /* Save the content of the edit field into the buffer */
  346.         save();
  347.     }
  348.     return ret;
  349. }
  350. /*
  351.     Multiple field dialog.
  352.     All field are shown one under each others
  353.  */
  354. PUBLIC MENU_STATUS DIALOG::edit(
  355.     const char *_title,        // Main title
  356.     const char *_intro,        // Mini help describing the purpose
  357.                     // of the dialog
  358.     HELP_FILE &helpfile,    // Help text in a file or NULL
  359.     int &nof,            // Start editing on which field
  360.                     // Will contain the current field.
  361.     int but_options)        // MENUBUT_xxxxx
  362. {
  363.     return edit (_title,_intro,helpfile.getpath(),nof,but_options);
  364. }
  365.  
  366. /*
  367.     Multiple field dialog.
  368.     All field are shown one under each others
  369. */
  370. PUBLIC MENU_STATUS DIALOG::edit(
  371.     const char *_title,        // Main title
  372.     const char *intro,        // Mini help describing the purpose
  373.                     // of the dialog
  374.     const char *helpfile,        // Help text in a file or NULL
  375.     int nof)            // Start editing on which field
  376. {
  377.     return edit (_title,intro,helpfile,nof
  378.         ,MENUBUT_ACCEPT|MENUBUT_CANCEL);
  379. }
  380.  
  381. /*
  382.     Multiple field dialog.
  383.     All field are shown one under each others
  384. */
  385. PUBLIC MENU_STATUS DIALOG::edit(
  386.     const char *_title,        // Main title
  387.     const char *intro,        // Mini help describing the purpose
  388.                     // of the dialog
  389.     HELP_FILE &helpfile,    // Help text in a file or NULL
  390.     int nof)            // Start editing on which field
  391. {
  392.     return edit (_title,intro,helpfile.getpath(),nof);
  393. }
  394.  
  395.  
  396. #ifdef TEST
  397.  
  398. #include "../translate/translat.h"
  399.  
  400. int main (int argc, char *argv[])
  401. {
  402.     translat_load ("/tmp","linuxconf-msg-" REVISION ".eng");
  403.     init_dialog();
  404.     DIALOG dia;
  405.     char str1[80]; str1[0] = '\0';
  406.     char str2[100]; strcpy (str2,"Hello");
  407.     SSTRING pass;
  408.     char addr[10];  addr[0] = '\0';
  409.     dia.newf_str ("Question 1",str1,sizeof(str1)-1);
  410.     dia.newf_str ("Other",str2,sizeof(str2)-1);
  411.     char chk = 0;
  412.     dia.newf_chk ("Option",chk,"more option");
  413.     dia.newf_pass ("Password",pass);
  414.     dia.newf_str ("Address",addr,sizeof(addr)-1);
  415.     SSTRING addr2;
  416.     FIELD_COMBO *comb = dia.newf_combo ("Combo",addr2);
  417.     comb->addopt("opt 1");
  418.     comb->addopt("opt 2");
  419.     comb->addopt("opt 3");
  420.     comb->addopt("opt 4");
  421.     SSTRING addr3;
  422.     dia.newf_str ("sstring",addr3);
  423.     dia.edit ("This is a test",NULL,NULL,0);
  424.     dia.newf_str ("Other",str2,sizeof(str2)-1);
  425.     dia.newf_str ("Other",str2,sizeof(str2)-1);
  426.     dia.newf_str ("Other",str2,sizeof(str2)-1);
  427.     dia.newf_str ("Other",str2,sizeof(str2)-1);
  428.     dia.newf_str ("Other",str2,sizeof(str2)-1);
  429.     dia.newf_str ("Other",str2,sizeof(str2)-1);
  430.     dia.newf_str ("Other",str2,sizeof(str2)-1);
  431.     dia.newf_str ("Other",str2,sizeof(str2)-1);
  432.     dialog_settimeout (15,MENU_ESCAPE,1);
  433.     dia.edit ("This is a test"
  434.         ,"Please you must reenter the\n"
  435.          "value\n"
  436.          "or accept it\n"
  437.         ,"helpfile"
  438.         ,2);
  439.     endwin();
  440.     printf ("Question 1 :%s:\n",str1);
  441.     printf ("Other      :%s:\n",str2);
  442.     printf ("Option     :%s:\n",chk ? "Selected" : "Not selected");
  443.     printf ("Password   :%s:\n",pass.get());
  444.     printf ("Address    :%s:\n",addr);
  445.     printf ("Address  2 :%s:\n",addr2.get());
  446.     printf ("Address  3 :%s:\n",addr3.get());
  447.     return 0;
  448. }
  449.  
  450. #endif
  451.  
  452.